/* 3DGo Game
 * Copyright (C) 2008 Roman Hwang, Eugene Melnichek

 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation - version 2
 * of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "GTPInterface.h"

#include "Logger.h"

#include <algorithm>

//////////////////////////////////////////////////////////////////////////

GTPInterface::GTPInterface()
: m_runner("gnugo.exe", " --mode gtp"), m_boardSize(0)
{
	
}

//////////////////////////////////////////////////////////////////////////

GTPInterface::~GTPInterface()
{
	Quit();	
}

//////////////////////////////////////////////////////////////////////////

GTPInterface* GTPInterface::GetInstance()
{
	static GTPInterface gtpInterface;
	return &gtpInterface;
}

//////////////////////////////////////////////////////////////////////////

bool IsNotValitSymbol(const char _symbol)
{
	return (_symbol != '.' && 
			_symbol != 'X' && 
			_symbol != 'O' && 
			_symbol != '+');
}

//////////////////////////////////////////////////////////////////////////

void GTPInterface::CleanBoard(char* _board)
{
	std::string board(_board);
	board.replace( board.find("O P"), 1, "");
	board.replace( board.find("O P"), 1, "");
	board.replace( board.find("(X)"), 3, "");
	board.replace( board.find("(O)"), 3, "");
	std::replace_if(	board.begin(), 
					board.end(),
					IsNotValitSymbol,
					' ');
	//board.replace( board.find(" "), 1, "");
	memset(_board, 0, strlen(_board));
	for(int i = 0, k = 0, size = board.size(); i < size; ++i)
	{
		if (board[i] == ' ')
			continue;
		_board[k] = board[i];
		++k;
	}
}

//////////////////////////////////////////////////////////////////////////

void GTPInterface::SetBoardSize(int _boardSize)
{
	char buffer[10];
	DWORD dwRead;
	char command[20] = "boardsize ";
	char number[3] = {0};
	_itoa(_boardSize, number, 10);
	strcat_s(command, 20, number);
	strcat_s(command, 20, "\n");
	//strcat(command, number);
	m_runner.SendInput(command, strlen(command));
	m_runner.GetOutput(buffer, 10, &dwRead);
	m_boardSize = _boardSize;
}

//////////////////////////////////////////////////////////////////////////

int GTPInterface::GetBoardSize() const
{
	// Get board size from gnugo.
	if (m_boardSize == 0)
	{
		// TODO: Replace to create command and get board size from gnugo
		int dummy = 19;
		return dummy;
	}
	return m_boardSize;

}

//////////////////////////////////////////////////////////////////////////

std::string GTPInterface::GetBoard()
{
	WRITELINELOG("Getting board...");

	char buffer[1500] = {0};
	DWORD dwRead;
	
	std::string command("showboard\n");
	m_runner.SendInput(command.c_str(), command.length());
	m_runner.GetOutput(buffer, 1500, &dwRead);
	// If not everything read
	while (dwRead <= 6)
	{
		Sleep(50);
		m_runner.GetOutput(buffer, 1500, &dwRead);
		WRITELOG("Output from GetOutput: ");
		WRITELINELOG(buffer);
	}
	CleanBoard(buffer);

	WRITELINELOG("Board getting complete.");
	WRITELOG("Buffer size:");
	WRITELINELOG(strlen(buffer));

	return std::string(buffer);
	
}

//////////////////////////////////////////////////////////////////////////

bool GTPInterface::MakeMove(const GTPMove& _move)
{
	WRITELOG("Making move...");

	char command[16];
	char *buffer = (_move.GetColor() == WHITE) ? "white " : "black ";

	WRITELOG(buffer);

	strcpy(command, buffer);
	char moveInChars[4] = {0};
	_move.GetChars(moveInChars);
	strcat(command, moveInChars);
	strcat(command, "\n");
	bool result = m_runner.SendInput(command, 16);

	DWORD dwRead;
	do
	{
		m_runner.GetOutput(command, 16, &dwRead);
	} while(dwRead < 1);

	WRITELINELOG("Move made...");

	return result;
}

//////////////////////////////////////////////////////////////////////////


bool GTPInterface::GenerateMove(Color _color)
{
	WRITELINELOG("Generating move...");

	char buffer[20] = {0};
	std::string command("genmove ");
	command += ColorToChar(_color);
	command += "\n";
	bool result = m_runner.SendInput(command.c_str(), command.length());
	if (result)
	{
		DWORD dwRead;
		do
		{
			m_runner.GetOutput(buffer, 20, &dwRead);
			WRITELINELOG("Output");
			WRITELINELOG(buffer);

			// Check is last move PASS
			_isLastMovePass = (strstr(buffer, "pass") != NULL);
		}
		while(dwRead <= 1);
	}
	
	WRITELINELOG("Generating complete");

	return result;
}


//////////////////////////////////////////////////////////////////////////

void GTPInterface::Quit()
{
	m_runner.SendInput("quit\n", 5);
}

//////////////////////////////////////////////////////////////////////////


bool GTPInterface::IsLastMovePass() const
{
	return _isLastMovePass;
}


//////////////////////////////////////////////////////////////////////////


std::string GTPInterface::GetFinalScore()
{
	char buffer[20] = {0};
	std::string command("final_score");
	bool result = m_runner.SendInput(command.c_str(), command.length());
	if (result)
	{
		DWORD dwRead;
		do
		{
			m_runner.GetOutput(buffer, 20, &dwRead);
			WRITELINELOG("Output");
			WRITELINELOG(buffer);
		}
		while(dwRead <= 1);
	}
	return buffer;
}


//////////////////////////////////////////////////////////////////////////
